﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//
using EncryptProject;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using CommonBase;


namespace SoftKeyLib
{
    /// <summary>
    /// 加密锁操作类
    /// </summary>
    public class SoftKeyOperation
    {
        #region 常量

        /// <summary>
        /// 加密字符串长度，即：MD5 值长度
        /// </summary>
        public const short KEYSTRING_LENGTH = 32;
        /// <summary>
        /// MD5 加密字符串格式（对公司）
        /// </summary>
        public const string MD5_FORMAT_STYLE4COMPANY = "MachineNum: {0}; MendTime: {1}; GUID: {2}";
        /// <summary>
        /// MD5 加密字符串格式（对用户）
        /// </summary>
        public const string MD5_FORMAT_STYLE4USER = "MD5: {0}; SoftKeyID: {1};";
        /// <summary>
        /// 储存器中的数据
        /// </summary>
        public const string KEY_EPROM = "文轩VV";

        const string HKEY_READ = "AA7652E1"; // 读
        const string LKEY_READ = "D218F16F";
        const string HKEY_WRITE = "4B4FDC73"; // 写
        const string LKEY_WRITE = "47528B8B";

        #endregion

        #region 变量

        SoftKey ytSoftKey = new SoftKey(); // 初始化操作加密锁的类
        static string keyPath = string.Empty;

        #endregion

        #region 公开的方法

        /// <summary>
        /// 用于返回加密锁的 ID 号，加密锁的ID号由两个长整型组成。【no use】
        /// <para>注：该方法有个缺陷，新锁或重新初始化旧锁后，ID 为全 F</para>
        /// <para>提示1：锁的 ID 是每一把都是唯一的，每一把是唯一的是指每一把锁的 ID 都不相同</para>
        /// <para>提示2: ID 唯一是指两个 ID 转化为 16 进制字符串后并连接起来后是唯一的</para>
        /// </summary>
        /// <returns></returns>
        public string GetSoftKeyID()
        {
            int id_1 = 0, id_2 = 0;
            if (ytSoftKey.GetID(ref id_1, ref id_2, keyPath) != 0)
                return string.Empty;
            else
                return string.Format("{0}{1}", id_1.ToString("X"), id_2.ToString("X"));
        }

        /// <summary>
        /// 获取芯片唯一 ID
        /// </summary>
        /// <returns></returns>
        public string GetChipID()
        {
            string outChipID = string.Empty;
            if (ytSoftKey.GetChipID(ref outChipID, keyPath) != 0)
                return null;
            else
                return outChipID;
        }

        /// <summary>
        /// 简单寻找加密锁，判断系统中是否存在着加密锁，不需要是指定的加密锁
        /// </summary>
        /// <param name="hwndHandle">控件绑定到的窗口句柄，包含控件的窗口句柄 (HWND)</param>
        /// <returns></returns>
        public bool EasyFindSoftKey(IntPtr hwndHandle)
        {
            if (ytSoftKey.FindPort(0, ref keyPath) == 0) // 判断系统中是否存在着加密锁，不需要是指定的加密锁
            {
                registerDeviceNotification(hwndHandle); // 注册加密锁事件插拨通知
                return true;
            }

            return false;
        }

        /// <summary>
        /// 寻找加密锁
        /// </summary>
        /// <returns></returns>
        public bool FindSoftKey()
        {
            // 检查是否存在指定的加密锁
            return ytSoftKey.CheckKeyByFindort_2() == 0 && // 使用普通算法一
                ytSoftKey.CheckKeyByEncstring() == 0 && // 使用增强算法一
                ytSoftKey.CheckKeyByEncstring_New() == 0; // 使用增强算法二
            //&& ytSoftKey.CheckKeyByReadEprom() == 0; // 使用读写储存器
        }

        /// <summary>
        /// 增强方式寻找加密锁（+ 从储存器读取相应数据的方式）
        /// </summary>
        /// <returns></returns>
        public bool FindSoftKeyPro()
        {
            // 检查是否存在指定的加密锁
            return ytSoftKey.CheckKeyByFindort_2() == 0 && // 使用普通算法一
                ytSoftKey.CheckKeyByEncstring() == 0 && // 使用增强算法一
                ytSoftKey.CheckKeyByEncstring_New() == 0 && // 使用增强算法二
                ytSoftKey.CheckKeyByReadEprom() == 0; // 从储存器读取相应数据的方式
            //&& ytSoftKey.CheckKeyByReadEprom() == 0; // 使用读写储存器
        }

        /// <summary>
        /// 写入信息到加密锁中
        /// </summary>
        /// <param name="writeString">写入的字符串</param>
        /// <returns>写入成功与否</returns>
        public bool PutString2SoftKey(string writeString)
        {
            int ret = ytSoftKey.YWriteString(writeString, 0, HKEY_WRITE, LKEY_WRITE, keyPath);
            if (ret != 0)
                return false;
            else
                return true;
        }

        /// <summary>
        /// 从加密锁中读信息
        /// </summary>
        /// <param name="readString">读出的字符串</param>
        /// <returns>读出成功与否</returns>
        public bool GetStringFromSoftKey(ref string readString)
        {
            int ret = ytSoftKey.YReadString(ref readString, 0, KEYSTRING_LENGTH, HKEY_READ, LKEY_READ, keyPath);
            if (ret != 0)
                return false;
            else
                return true;
        }

        /// <summary>
        /// 加密锁状态改变
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="isExitApp">是否退出应用程序</param>
        public void OnDeviceChange(ref Message msg, bool isExitApp)
        {
            int wParam = (int)msg.WParam;
            if (wParam == Win32.DBT_DEVICEARRIVAL)
            {
                int devType = Marshal.ReadInt32(msg.LParam, 4);
                if (devType == Win32.DBT_DEVTYP_DEVICEINTERFACE)
                {
                    Win32.DEV_BROADCAST_DEVICEINTERFACE1 DeviceInfo =
                        (Win32.DEV_BROADCAST_DEVICEINTERFACE1)Marshal.PtrToStructure(msg.LParam,
                        typeof(Win32.DEV_BROADCAST_DEVICEINTERFACE1));
                    //if (ytSoftKey.CheckKeyByFindort_2() == 0)
                    //    MessageBox.Show("加密锁已插入", ConstantString.MSG_COMPANY);
#if DEBUG
                    Debug.WriteLine("加密锁已插入！");
#endif
                }
            }
            if (wParam == Win32.DBT_DEVICEREMOVECOMPLETE) // 收到硬件拨出信息后，调用检查锁函数来检查是否锁被拨出
            {
                Win32.DEV_BROADCAST_DEVICEINTERFACE1 DeviceInfo =
                    (Win32.DEV_BROADCAST_DEVICEINTERFACE1)Marshal.PtrToStructure(msg.LParam,
                    typeof(Win32.DEV_BROADCAST_DEVICEINTERFACE1));
                // 这里使用 CheckKeyByFindort_2 检查加密锁是否被拨出，也可以使用其它检查锁函数来检查加密锁是否被拨出
                if (ytSoftKey.CheckKeyByFindort_2() != 0)
                {
                    MessageBox.Show("注意：加密锁被拨出！", ConstantString.MSG_COMPANY);
                    if (isExitApp)
                        Application.Exit();
                }
            }
        }

        #endregion

        #region 私有方法

        /// <summary>
        /// 注册加密锁事件插拨通知
        /// </summary>
        /// <param name="hwndHandle">控件绑定到的窗口句柄，包含控件的窗口句柄 (HWND)</param>
        void registerDeviceNotification(IntPtr hwndHandle)
        {
            Win32.DEV_BROADCAST_DEVICEINTERFACE dbi = new Win32.DEV_BROADCAST_DEVICEINTERFACE();
            int size = Marshal.SizeOf(dbi);
            dbi.dbcc_size = size;
            dbi.dbcc_devicetype = Win32.DBT_DEVTYP_DEVICEINTERFACE;
            dbi.dbcc_reserved = 0;
            dbi.dbcc_classguid = Win32.GUID_DEVINTERFACE_USB_DEVICE;
            dbi.dbcc_name = 0;
            IntPtr buffer = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(dbi, buffer, true);
            IntPtr r = Win32.RegisterDeviceNotification(hwndHandle, buffer, Win32.DEVICE_NOTIFY_WINDOW_HANDLE);

            if (r == IntPtr.Zero)
                MessageBox.Show(Win32.GetLastError().ToString(), ConstantString.MSG_COMPANY);
        }

        #endregion
    }
}
